#include "audiooutput.h"

AudioOutput::AudioOutput(AVSync *avsync, AVRational time_base, const AudioParams &audio_params, AVFrameQueue *frame_queue)
    : avsync_(avsync), time_base_(time_base), src_tgt_(audio_params), frame_queue_(frame_queue)
{

}

AudioOutput::~AudioOutput()
{

}

void fill_audio_pcm(void *udata, Uint8 *stream, int len)
{
    // 1.从frame queue读取解码后的pcm数据填充到stream；
    // 2.len = 4000字节 ， 一个frame = 8000字节，一次读取了4000，还剩4000
    AudioOutput *is = (AudioOutput *)udata;
    int len1 = 0;
    int audio_size = 0;

    while (len > 0) {
        if(is->audio_buf_index == is->audio_buf_size) {
            is->audio_buf_index = 0;
            AVFrame *frame = is->frame_queue_->Pop(10);
            if(frame) {
                is->pts_ = frame->pts;
                //读到pcm数据
                //怎么判断重采样
                if(( (frame->format != is->dst_tgt_l.fmt) ||
                     (frame->sample_rate != is->dst_tgt_l.freq) ||
                     (frame->channel_layout != is->dst_tgt_l.channel_layout)) &&
                    (!is->swr_ctx_)) {
                    //需要重采样
                    is->swr_ctx_ = swr_alloc_set_opts(
                        NULL,
                        is->dst_tgt_l.channel_layout,
                        (enum AVSampleFormat)is->dst_tgt_l.fmt,
                        is->dst_tgt_l.freq,
                        frame->channel_layout,
                        (enum AVSampleFormat)frame->format,
                        frame->sample_rate,
                        0,
                        NULL);

                    if(!is->swr_ctx_ || swr_init(is->swr_ctx_) < 0) {
                        qDebug() <<" swr_init : "<< "err";
                        swr_free((SwrContext**)(&is->swr_ctx_));
                        return;
                    }
                }

                if(is->swr_ctx_) { //重采样
                    const uint8_t **in = (const uint8_t**)frame->extended_data;
                    uint8_t **out = &is->audio_buf1_;

                    int out_samples = frame->nb_samples * is->dst_tgt_l.freq/frame->sample_rate + 256;
                    int out_bytes = av_samples_get_buffer_size(NULL, is->dst_tgt_l.channeles, out_samples, is->dst_tgt_l.fmt, 0);
                    if(out_bytes < 0) {
                        qDebug() <<" out_bytes < 0"<< "";
                        return;
                    }

                    av_fast_malloc(&is->audio_buf1_, &is->audio_buf1_size, out_bytes);

                    int len2 = swr_convert(is->swr_ctx_, out, out_samples, in, frame->nb_samples); //返回样本数
                    if(len2 < 0) {
                        qDebug() <<" swr_convert err"<< "";
                        return;
                    }
                    is->audio_buf_ = is->audio_buf1_;
                    is->audio_buf_size = av_samples_get_buffer_size(NULL, is->dst_tgt_l.channeles, len2, is->dst_tgt_l.fmt, 0);
                } else { //没有重采样
                    audio_size = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, (enum AVSampleFormat)frame->format, 1);
                    av_fast_malloc(&is->audio_buf1_, &is->audio_buf1_size, audio_size);
                    is->audio_buf_ = is->audio_buf1_;
                    is->audio_buf_size = audio_size;
                    memcpy(is->audio_buf_, frame->data[0], audio_size);
                }

                av_frame_free(&frame);
            } else {
                //没读到pcm数据
                is->audio_buf_ = nullptr;
                is->audio_buf_size = 512;
            }
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if(len1 > len) len1 = len;

        if(!is->audio_buf_) {
            memset(stream, 0, len1);
        } else {
            //真正的有效数据
            memcpy(stream, is->audio_buf_ + is->audio_buf_index, len1);
        }

        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }

    //设置时钟
    if(is->pts_ != AV_NOPTS_VALUE) {
        double pts = is->pts_ * av_q2d(is->time_base_);
        is->avsync_->SetClock(pts);
        qDebug() <<" audio pts : "<< pts;
    }
}

int AudioOutput::Init()
{
    if(SDL_Init(SDL_INIT_AUDIO) != 0) {
        qDebug() <<" SDL_Init err : "<< "";
        return -1;
    }

    SDL_AudioSpec wanted_spec, spec;
    wanted_spec.channels = src_tgt_.channeles;
    wanted_spec.freq = src_tgt_.freq;
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.silence = 0; //静音时候什么样式
    wanted_spec.callback = fill_audio_pcm;
    wanted_spec.userdata = this;
    wanted_spec.samples = src_tgt_.frame_size; //每次回调需要多少数据，采样数量

    int ret = SDL_OpenAudio(&wanted_spec, &spec);
    if(ret < 0) {
        return -1;
    }

    dst_tgt_l.channeles = spec.channels;
    dst_tgt_l.fmt = AV_SAMPLE_FMT_S16;
    dst_tgt_l.freq = spec.freq;
    dst_tgt_l.channel_layout = av_get_default_channel_layout(spec.channels);
    dst_tgt_l.frame_size = src_tgt_.frame_size;

    SDL_PauseAudio(0);
    qDebug() <<" AudioOutput::Init() : "<< "finish";
    return 0;
}

int AudioOutput::DeInit()
{
    SDL_PauseAudio(1);
    SDL_CloseAudio();
    qDebug() <<" AudioOutput::DeInit() : "<< "finish";
    return 0;
}
